Ext.ns('Kohive', 'Kohive.app', 'Kohive.models', 'Kohive.controllers',
		'Kohive.views', 'Kohive.exception', 'Kohive.QuickApp', 'Kohive.ux'
);

/*
 * Kohive.OS
 * @extends ExtMVC.OS
 * Specialisation of ExtMVC.OS, creates and manages various Kohive OS elements
 */
Kohive.OS = function(config) {
	var config = config || {};

	// super (ExtMVC.OS)
	Kohive.OS.superclass.constructor.call(this, config);

	/**
	 * @property ircManager
	 * @type Ext.ux.IRC.Manager
	 * A global IRC manager instance 
	 */
	this.ircManager = new Ext.ux.IRC.Manager({
				autoConnect	: false,
				server		: {
					serverHost			: 'irc.kohive.com',
					serverPort			: 8667,
					serverPolicyPort	: 16666,
					password			: 'secret123',
					proxySwfPath		: '/IrcProxy.swf',
					showLogMessages		: false
				}
			});

	/**
	 * FIXME: No no no this shouldn't be here.  It should be in a controller but Ext MVC
	 * is too shit :(.  Wait for v0.6
	 */
	this.on('membersload', function() {
				var manager = Kohive.OS.ircManager;

				if (!manager.proxy.connected) {
					var idCard = this.getIdCardData();
					var userName = String.format("KohiveUser--{0}",
							this.currentUser.get('id')
					);
					Ext.apply(manager.proxy, {
								nickname	: userName,
								realname	: userName
							});

					manager.proxy.connect();
				}
			}, this);

	this.on('launch', this.loadSession, this);
};

Ext.extend(Kohive.OS, ExtMVC.OS, {
	usesHistory						: true,
	dispatchHistoryOnLoad			: false,
	viewportBuilder					: 'kohive',

	/**
	 * Maintains a reference to the currently loaded Hive
	 */
	currentHive						: null,

	/**
	 * Maintains a reference to the currently logged in user
	 */
	currentUser						: null,

	/**
	 * Maintains a reference to the current user membership
	 */
	currentMemberships				: null,

	/**
	 * Maintains a reference to the current hives memberships
	 */
	currentHiveMemberships			: null,

	/**
	 * @property initialized
	 * @type Boolean
	 * Tracks the initialization status.  This is set to true after onLaunch() is run. Private
	 */
	initialized						: false,

	/**
	 * Initializes the Kohive application, sets up Viewport and other OS objects
	 * Call this with Ext.onReady
	 * @return {Boolean} True if initialization was successful or had already occured (test this independently with isInitialized())
	 */
	onLaunch						: function() {
		if (!this.initialized) {
			// Initialise the hives and members controllers, attaches events
			// this.hives = this.getController('hives');
			// this.members = this.getController('members');
			var os = this;

			if (!this.isDevelopment()) {
				this.startRunners();
			} else {
				var hives = this.getController('hives');
				var members = this.getController('members');
			}

			// Add the background container
			this.bgImageEl = Ext.getBody().createChild({
						tag	: 'img',
						cls	: 'background-image',
						// src: Kohive.url('resources', 'images/backgrounds/wallpaper1.jpg'),
						id	: 'kohive-background-image'
					});

			this.addStickiesWrapperToDesktop();

			// Resize the background on window resize
			var obj = this;
			$(window).bind('resize', function() {
						obj.bgImageEl.setWidth(Ext.getBody().getWidth());
						obj.bgImageEl.setHeight(Ext.getBody().getHeight());
					});

			// Start sending pings to the server so it knows when the user is online
			// this.initLastSeenOnline();

			// preload images on the site
			this.preloadImages();

			// Add an event to listen to hiveload so we can update the hive when done
			this.on('hiveload', this.updateHiveBackground, this);
			this.on('membersload', this.initHistory, this);
			// this.on('user-loaded', this.checkForFirstLogin, this);

			this.initialized = true;
		};

		return this.initialized;
	},

	/**
	 * Checks if we are viewing the site on kohive.com, if so, return false
	 */
	isDevelopment					: function() {
		var regexp = new RegExp('kohive.com');
		// Can be turned on in development mode now, too, since the ping request isn't that annoying anymore
		return false; // !regexp.test(location.host);
	},

	loadMembers						: function() {
		var hives = this.getController('hives');
		var members = this.getController('members');

		if (!this.getCurrentHive())
			return;
		hives.fireAction('refresh', this);
		members.fireAction('loadMembers', this, [this.getMemberPanel(), null,
						false]);
	},

	startRunners					: function() {
		// Initialise the hives and members controllers, attaches events
		var hives = this.getController('hives');
		var members = this.getController('members');
		var os = this;

		this.loopingMode = true;

		// this.loadMembersTask = {
		// run: function() {
		// if (!this.getCurrentHive()) return;
		// hives.fireAction('refresh', this);
		// members.fireAction('loadMembers', this, [this.getMemberPanel(), null, false]);
		// },
		// scope: this,
		// interval: 25000 // 15 seconds
		// };

		this.checkUpdatesTask = {
			run			: function() {
				// if (Kohive.OS.membersLoaded && Kohive.OS.applicationsLoaded) {
				this.checkForUpdates();
				// }
			},
			scope		: this,
			interval	: 5000
			// 5 seconds
		};

		this.checkUpdatesTaskRunner = new Ext.util.TaskRunner();
		this.checkUpdatesTaskRunner.start(this.checkUpdatesTask);

		// this.loadMembersTaskRunner = new Ext.util.TaskRunner();
		// this.loadMembersTaskRunner.start(this.loadMembersTask);
	},

	stopRunners						: function() {
		// // Initialise the hives and members controllers, attaches events
		// var hives = this.getController('hives');
		// var members = this.getController('members');
		//    
		this.loopingMode = false;

		if (this.checkUpdatesTaskRunner)
			this.checkUpdatesTaskRunner.stopAll();

		// if (this.loadMembersTaskRunner)
		// this.loadMembersTaskRunner.stopAll();
	},

	/**
	 * Enables the loop to update the site
	 */
	enableLoops						: function() {
		this.productionMode();
	},

	// /**
	// * Enables the loop to update the site
	// */
	// disableLoops: function() {
	// this.developmentMode();
	// },

	initHistory						: function() {
		Kohive.OS.handleHistoryChange(window.document.location.hash);

		this.un('membersload', this.initHistory, this);
	},

	pinging							: false,

	/**
	 * Pings the server and checks if there are any updates. If there is, it then
	 * fires off the proper actions/events
	 */
	checkForUpdates					: function() {
		if (this.fireEvent('before-ping') !== false) {
			if (!this.getCurrentHive())
				return;
			if (this.pinging === true)
				return;

			// TODO move this to the proper way below
			// reload the applications
			// this.getApplicationLauncher().populateFromHive(true);

			this.pinging = true;

			// check for updates
			var updates = Kohive.models.Update.findAll({
				url			: this.scopedUrl('ping'),
				baseParams	: {
					hive_id	: this.getCurrentHiveId()
				},
				listeners	: {
					scope			: this,
					'loadexception'	: function() {
						Kohive.OS.un('before-ping', Kohive.OS.returnFalse,
								Kohive.OS
						);
						this.pinging = false;
					},
					'load'			: function(store) {
						this.pinging = false;
						// if the store count is over 0, then show the message
						if (store.getTotalCount() > 0) {
							store.each(function(record) {
								if (record.get('part') == "messages") {
									this.getController('members')
											.fireAction('loadMessages');
								} else if (["members", "member-went-online",
										"member-went-offline", "memberships",
										"applications", "hives"]
										.hasObject(record.get('part'))) {
									this.loadMembers();
									this.getApplicationLauncher()
											.populateFromHive(true);
									Kohive.OS.desktopStickiesDataview.store
											.reload();
								} else if (record.get('part') == 'desktop-stickies') {
									Kohive.OS.desktopStickiesDataview.store
											.reload();
								}
							}, this
							);
						} else {
							Kohive.OS.un('before-ping', Kohive.OS.returnFalse,
									Kohive.OS
							);
						};
					}
				}
			}
			);
		};
	},

	/**
	 * Returns false for events
	 */
	returnFalse						: function() {
		return false;
	},

	/**
	 * 
	 */
	updateHiveBackground			: function(hive) {
		if (!hive)
			return;

		// Get the hive data
		var hive = hive.data.hive;

		// Update the background colour/image
		this.setBackgroundColour(hive.background_image || null);

		this.updateDesktopStickies();
	},

	getBackgroundColours			: function() {
		if (!this.defaultBackgroundColours) {
			this.defaultBackgroundColours = new Ext.data.SimpleStore({
				fields	: ['name', 'image', 'thumb', 'hex'],
				data	: [
						['blue', '#0C6B9C',
								'/images/wallpapers/thumbs/0C6B9C.jpg'],
						['pink', '#DED8F2',
								'/images/wallpapers/thumbs/d577cf.jpg'],
						['grey', '#D8D8D9',
								'/images/wallpapers/thumbs/bbbbbb.jpg'],
						['lightblue', '#D2E0EF',
								'/images/wallpapers/thumbs/8cc001.jpg'],
						['greyblue', '#768294',
								'/images/wallpapers/thumbs/dc9703.jpg'],
						['darkblue', '#002841',
								'/images/wallpapers/thumbs/dark.jpg', '#002841'],
						['white', '#EFEFEF',
								'/images/wallpapers/thumbs/white.jpg',
								'#EFEFEF'],
						['black', '#000000',
								'/images/wallpapers/thumbs/black.jpg',
								'#000000'],
						['1', '/images/wallpapers/1.jpg',
								'/images/wallpapers/thumbs/1.jpg', '#0C6B9C'],
						['3', '/images/wallpapers/3.jpg',
								'/images/wallpapers/thumbs/3.jpg', '#0C6B9C'],
						['15', '/images/wallpapers/15.jpg',
								'/images/wallpapers/thumbs/15.jpg', '#0C6B9C'],
						['2', '/images/wallpapers/2.jpg',
								'/images/wallpapers/thumbs/2.jpg', '#0C6B9C'],
						['6', '/images/wallpapers/6.jpg',
								'/images/wallpapers/thumbs/6.jpg', '#0C6B9C'],
						['12', '/images/wallpapers/12.jpg',
								'/images/wallpapers/thumbs/12.jpg', '#0C6B9C'],
						['10', '/images/wallpapers/10.jpg',
								'/images/wallpapers/thumbs/10.jpg', '#0C6B9C'],
						['11', '/images/wallpapers/11.jpg',
								'/images/wallpapers/thumbs/11.jpg', '#0C6B9C'],
						['13', '/images/wallpapers/13.jpg',
								'/images/wallpapers/thumbs/13.jpg', '#0C6B9C'],
						['4', '/images/wallpapers/4.jpg',
								'/images/wallpapers/thumbs/4.jpg', '#0C6B9C'],
						['5', '/images/wallpapers/5.jpg',
								'/images/wallpapers/thumbs/5.jpg', '#0C6B9C'],
						['14', '/images/wallpapers/14.jpg',
								'/images/wallpapers/thumbs/14.jpg', '#0C6B9C'],
						['16', '/images/wallpapers/16.jpg',
								'/images/wallpapers/thumbs/16.jpg', '#0C6B9C']]
			}
			);
		};

		return this.defaultBackgroundColours;
	},

	/**
	 * Sets the background colour of the site. If none is set then it reverts to the original (blue)
	 * @param {String/Integer} colour The colour/Url for the background
	 * @param {Object} save True if you want to save it to the server. Defaults to false
	 */
	setBackgroundColour				: function(colour, save) {
		this.bgImageEl.dom.src = "";
		this.bgImageEl.hide();
		Ext.getBody().applyStyles('background:#0C6B9C');

		if (!colour) {
			return;
		};

		var colourOrginal = colour;
		colour = (typeof colour == "object") ? colour.image : colour;

		// Check if we need to save it
		// Save it if specified
		if (save) {
			var hive = new Kohive.models.Hive(this.getCurrentHive().data.hive);
			hive.set('background_image', colour);

			var config = (typeof save == "object") ? save : {};

			Ext.applyIf(config, {
						url	: '/hives/' + this.getCurrentHive().data.hive.id
					});

			// Save the hive
			hive.save(config);
		};

		// Check if it is a URL
		var isUrl = false;
		for (var i = 0; i < colour.length; i++) {
			if (colour[i] == "/") {
				isUrl = true;
			};
		};

		// If it is a Url, update the background image url
		if (isUrl) {
			// Set the source of the picture
			this.bgImageEl.dom.src = colour;

			// Set the width and height of the image
			this.bgImageEl.setWidth(Ext.getBody().getWidth());
			this.bgImageEl.setHeight(Ext.getBody().getHeight());

			Ext.getBody()
					.applyStyles('background:'
							+ colourOrginal.hex
							|| (this.getBackgroundColours().data.items[this
									.getBackgroundColours().find('image',
											colour
									)] || '#0C6B9C'));

			this.bgImageEl.show();

			return;
		};

		// Check if it is hashed
		var hashed = false;
		for (var i = 0; i < colour.length; i++) {
			if (colour[i] == "#") {
				hashed = true;
			};
		};

		if (hashed) {
			Ext.getBody().applyStyles('background:' + colour);
		} else {
			Ext.getBody().applyStyles('background:#' + colour);
		};
	},

	/**
	 * Attempts to load a hive from the window's location.  Takes everything after the #
	 * to be the hive url slug
	 */
	loadHiveFromUrl					: function() {
		var token = window.location.hash.replace('#', '').split("/")[0];

		// check if a token is set and if it exists
		if (!token || this.checkIfHiveExists(token) === false)
			return this.loadFromDefaultHiveId();

		// load the hive
		this.getController('hives').fireAction('loadHive', null, [token]);
	},

	/**
	 * Attempts to load a hive from the users default_hive_id. If it fails it will load the first hive in the users list
	 */
	loadFromDefaultHiveId			: function() {
		var user = this.getCurrentUser() || null;
		if (!user)
			return;

		// get the current memberships
		var memberships = this.getCurrentMemberships() || null;

		// If the current user has been loaded, get the default hive id
		var defaultHiveId = user.get('default_hive_id') || null;

		// check if the default hvie exists
		if (defaultHiveId) {
			var exists = this.checkIfHiveExists(defaultHiveId);
		};

		// Check if the current user has been loaded, if not, open the first hive
		if (!user || !defaultHiveId || !memberships.data.items[0]
				|| exists === false) {
			// If the memberships isn't found, the return an error
			if (!memberships)
				return Ext.Msg.alert('Load hive', '312:'
								+ Ext.ux.Translator
										.translate('something_wrong'));

			if (!memberships.data.items[0])
				return;

			// Get the first hive id from the first membership
			defaultHiveId = memberships.data.items[0].data.hive_id || null;
		};

		// Load the hive
		if (defaultHiveId)
			this.getController('hives').fireAction('loadHive', null,
					[defaultHiveId]
			);
	},

	checkIfHiveExists				: function(id) {
		var exists = false, memberships = this.getCurrentMemberships() || null;

		if (!id)
			return exists;

		memberships.each(function(membership) {
					if (membership.get('hive_id') == id) {
						exists = true;
					};
				}, this);

		return exists;
	},

	/**
	 * Returns an Ext.data.Store containing available colours for the header panel
	 * @return {Ext.data.Store} A simple store with allowed colours for the header panel
	 */
	getHeaderColours				: function() {
		if (!this.defaultHeaderColours) {
			this.defaultHeaderColours = new Ext.data.SimpleStore({
						fields	: ['colour', 'hex'],
						data	: [['blue', 'blue'], ['green', 'green'],
								['grey', 'grey'], ['pink', 'pink'],
								['yellow', 'yellow'], ['purple', 'purple'],
								['black', 'black'], ['red', 'red'],
								['lightblue', 'blue']

						]
					});
		};

		return this.defaultHeaderColours;
	},

	/**
	 * Attempts to retrieve session information from the server
	 */
	loadSession						: function(callback, scope) {
		Kohive.models.User.loadFromSession({
					success	: function(user) {
						this.currentUser = user;

						// Update the username
						Kohive.OS.getHeaderPanel().updateUsername();

						this.fireEvent('user-loaded', this.currentUser);

						if (callback && typeof callback == "function")
							callback.call(scope || this);
					},
					scope	: this
				});
	},

	/**
	 * Returns the viewport created by init()
	 * @return {Ext.Viewport} The Ext.Viewport for the Kohive app
	 */
	getViewport						: function() {
		return this.viewport;
	},

	/**
	 * Returns the Application Launcher
	 * @return {Kohive.ApplicationLauncher} The Application Launcher created on startup
	 */
	getApplicationLauncher			: function() {
		return this.applicationLauncher;
	},

	/**
	 * Returns the Quick Apps bar
	 * @return {Kohive.QuickAppsBar} The Quick Apps bar created on startup
	 */
	getQuickAppsBar					: function() {
		return this.quickAppsBar;
	},

	/**
	 * Returns the global HiveSummary component.
	 * @return {Kohive.HiveSummary} The shared global HiveSummary component.  See HiveSummary for usage
	 */
	getHiveSummary					: function() {
		return this.hiveSummary;
	},

	/**
	 * Returns the global HiveOptions component.
	 * @return {Kohive.HiveOptions} The shared global HiveOptions component.  See HiveOptions for usage
	 */
	getHiveOptions					: function() {
		return this.hiveOptions;
	},

	/**
	 * Returns the global Hive Panel component
	 * @return {Kohive.HivePanel} The shared global HivePanel component. See HivePanel for usage
	 */
	getHivePanel					: function() {
		return this.hivePanel;
	},

	/**
	 * Returns the global MemberSummary component.
	 * @return {Kohive.MemberSummary} The shared global MemberSummary component.  See MemberSummary for usage
	 */
	getMemberSummary				: function() {
		return this.memberSummary;
	},

	/**
	 * Returns the global MemberOptions component.
	 * @return {Kohive.MemberOptions} The shared global MemberOptions component.  See MemberOptions for usage
	 */
	getMemberOptions				: function() {
		return this.memberOptions;
	},

	/**
	 * Returns the global MemberPanel component
	 * @return {Kohive.MemberPanel} The shared global MemberPanel component. See MemberPanel for usage
	 */
	getMemberPanel					: function() {
		return this.memberPanel;
	},

	/**
	 * Returns the global Header Panel component
	 * @return {Kohive.HeaderPanel} The shared global HeaderPanel component. See HeaderPanel for usage
	 */
	getWidgetBar					: function() {
		return this.widgetBar;
	},

	/**
	 * Returns the global Header Panel component
	 * @return {Kohive.HeaderPanel} The shared global HeaderPanel component. See HeaderPanel for usage
	 */
	getHeaderPanel					: function() {
		return this.headerPanel;
	},

	/**
	 * Returns the global Window Group object
	 * @return {Ext.WindowGroup} The Window Group currently providing management for the whole application
	 */
	getWindowManager				: function() {
		return this.windowManager;
	},

	/**
	 * Returns a Kohive.models.User object for the currently logged in User,
	 * or null if no User is logged in.
	 * @return {Kohive.models.User/Null} The currently logged in user
	 */
	getCurrentUser					: function() {
		return this.currentUser;
	},

	/**
	 * Ridiculous method to get the Id Card the current user is using for the currently loaded hive
	 * @return {ExtMVC.Model.Base} The Id Card
	 */
	getIdCardData					: function() {
		var idCard, membership = this.getCurrentHive();
		Ext.each(this.getCurrentHiveMemberships() || [], function(mem) {
					if (mem.get('id') == membership.get('id')) {
						idCard = mem.data.id_card;
						return false;
					}
				}, this);

		return idCard;
	},

	/**
	 * Returns a Kohive.models.Hive object for the currently loaded Hive, or
	 * null if no Hive is loaded
	 * @return {Kohive.models.Hive/Null} The current loaded hive
	 */
	getCurrentHive					: function() {
		return this.currentHive;
	},

	getCurrentMembership			: function() {
		return this.getCurrentHive();
	},

	getCurrentMembershipId			: function() {
		return this.getCurrentHive().get('id');
	},

	/**
	 * Returns the current hive id
	 * @return {Int/Null} The current hive id
	 */
	getCurrentHiveId				: function() {
		return Kohive.OS.getCurrentHive().get('hive_id');
	},

	/**
	 * Updates the current hive with an instance of the current hive
	 * @param {Kohive.models.Hive} newHive
	 */
	setCurrentHive					: function(newHive, fireLoadEvent) {
		if (!this.isDevelopment())
			this.stopRunners();
		this.fireEvent('beforehiveload', this.currentHive);
		this.currentHive = newHive;

		if (fireLoadEvent !== false) {
			this.fireEvent('hiveload', newHive);
			if (!this.isDevelopment())
				this.startRunners.defer(500, this);
		};
	},

	/**
	 * Returns an array of Kohive.models.Membership objects for the currently loaded Hive, or
	 * null if no Hive is loaded
	 */
	getCurrentMemberships			: function() {
		return this.currentMemberships;
	},

	/**
	 * Updates the current memberships with an instance of all current memberships
	 */
	setCurrentMemberships			: function(newMemberships) {
		this.currentMemberships = newMemberships;
	},

	/**
	 * Returns a Kohive.models.Hive object for the currently loaded Hive, or
	 * null if no Hive is loaded
	 * @return {Kohive.models.Hive/Null} The current loaded hive
	 */
	getCurrentHiveMemberships		: function() {
		return this.currentHiveMemberships;
	},

	/**
	 * Updates the current membership with new memberships
	 * @param {Kohive.models.Membership} newMembership
	 */
	setCurrentHiveMemberships		: function(newMemberships) {
		this.currentHiveMemberships = newMemberships;

		this.fireEvent('membersload', newMemberships, true);
	},

	/**
	 * Returns a membership from an id card id
	 * @param {Int} id The id of the id card
	 * @param {Function} callback A method which will be called one the id card is loaded
	 */
	getIdCardFromId					: function(id, callback, scope) {
		if (!id || !callback) {
			return;
		};

		Kohive.models.IdCard.findById(id, {
					url		: '/memberships/'
							+ Kohive.OS.getCurrentHive().get('id')
							+ '/id_cards/' + id,
					success	: function(idCard) {
						callback.call(scope || this, idCard);
					},
					failure	: function() {
						Ext.Msg.alert('Error',
								'Sorry, something went wrong. Please try again'
						);
					}
				});
	},

	/**
	 * Returns a membership from an membership id
	 * @param {Int} id The id of the id card
	 */
	getIdCardFromMembershipId		: function(id, callback, scope) {
		if (!id || !callback) {
			return;
		};

		Kohive.models.IdCard.findById(id, {
					url		: '/memberships/' + id + '/id_card',
					success	: function(idCard) {
						callback.call(scope || this, idCard);
					},
					failure	: function() {
						Ext.Msg.alert('Error',
								'Sorry, something went wrong. Please try again'
						);
					}
				});
	},

	/**
	 * Runs a task every 1 minute to update the users last seen online field
	 */
	// initLastSeenOnline: function() {
	// var task = {
	// run: function() {
	// this.updateLastSeenOnline();
	// },
	// scope: this,
	// interval: 60000 // 1 minute
	// };
	// var runner = new Ext.util.TaskRunner();
	// runner.start(task);
	// },
	// 
	// /**
	// * Pings the server so that other users know that the current user is online
	// */
	// updateLastSeenOnline: function() {
	// return Ext.Ajax.request({
	// url: '/account/ping',
	// method: 'POST'
	// });
	// },
	/**
	 * Method which creates an empty hidden div in the body of the site and inserts
	 * certain images to pre-load them
	 */
	preloadImages					: function() {
		var images = [
				// window
				'/images/ext/kohive/x-window/body/left.png',
				'/images/ext/kohive/x-window/body/right.png',
				'/images/ext/kohive/x-window/body/bg.png',
				'/images/ext/kohive/x-window/body/left-corner.png',
				'/images/ext/kohive/x-window/body/right-corner.png',
				'/images/ext/kohive/x-window/body/bottom.png',

				'/images/ext/kohive/x-window/body/window-header-tl.png',
				'/images/ext/kohive/x-window/header/window-header-bg.png',
				'/images/ext/kohive/x-window/header/window-header-tr.png',
				'/images/ext/kohive/x-window/header/bug.png',
				'/images/ext/kohive/x-window/header/help.png',
				'/images/ext/kohive/x-window/header/maximize.png',
				'/images/ext/kohive/x-window/header/close.png',

				// icons
				'/images/apps/success.png',
				'/images/components/Universal/delete.png'];

		var el = Ext.getBody().createChild();
		el.hide();

		Ext.each(images, function(source) {
					el.createChild({
								tag	: 'img',
								src	: source
							});
				}, this);
	},

	/**
	 * Returns the default date on the site
	 */
	getDefaultDateFormat			: function() {
		return 'j M y';
	},

	/**
	 * Converts a Rails date into a valid ExtJS date for the site
	 * @param {String} field The field you want to convert to a date
	 * @param {Boolean} format True if you want to format the date to the default
	 */
	convertToDate					: function(field, format) {
		var dateStrings = field.split("T")[0].split("-");
		var day = parseInt(dateStrings[2], 10), month = parseInt(
				dateStrings[1], 10
		), year = parseInt(dateStrings[0], 10);
		var timeStrings = field.split("T")[1].split(":");
		var hour = parseInt(timeStrings[0], 10), min = parseInt(timeStrings[1],
				10
		), sec = parseInt(timeStrings[2], 10);

		var date = new Date(year, month - 1, day, hour, min, sec);

		// 21-Mar-09 @ 5:42pm
		if (format) {
			// return date.format('j-M-y @ g:ia');
			return date.format((typeof format == "string") ? format : Kohive.OS
					.getDefaultDateFormat());
		};

		return date;
	},

	/**
	 * Converts a database Rails date into a valid ExtJS date for the site
	 * @param {String} field The field you want to convert to a date
	 * @param {Boolean} format True if you want to format the date to the default
	 */
	convertToDateSpecial			: function(field, format) {
		var dateStrings = field.split(" ")[0].split("-");
		var day = parseInt(dateStrings[2], 10), month = parseInt(
				dateStrings[1], 10
		), year = parseInt(dateStrings[0], 10);
		var timeStrings = field.split(" ")[1].split(":");
		var hour = parseInt(timeStrings[0], 10), min = parseInt(timeStrings[1],
				10
		), sec = parseInt(timeStrings[2], 10);

		var date = new Date(year, month - 1, day, hour, min, sec);

		// 21-Mar-09 @ 5:42pm
		if (format) {
			// return date.format('j-M-y @ g:ia');
			return date.format((typeof format == "string") ? format : Kohive.OS
					.getDefaultDateFormat());
		};

		return date;
	},

	/**
	 * Checks if the current user is the author of the specified record
	 * @param {Ext.data.Record} record The record to check
	 */
	isAuthor						: function(record) {
		// check if anyone is logged in
		var current_user = this.getCurrentUser() || null;
		if (!current_user)
			return false;

		// check for current hive/membership
		var current_hive = this.getCurrentHive() || null;
		if (!current_hive)
			return false;

		if (!record.author_membership_id)
			return false;
		if (current_hive.data.id == record.author_membership_id)
			return true;

		return false;
	},

	/**
	 * Checks if the current user is the custom of the specified record
	 * @param {Ext.data.Record} record The record to check
	 */
	isCustom						: function(record, fieldA, fieldB) {
		// check if anyone is logged in
		var current_user = this.getCurrentUser() || null;
		if (!current_user)
			return false;

		// check for current hive/membership
		var current_hive = this.getCurrentHive() || null;
		if (!current_hive)
			return false;

		if (!record[fieldA])
			return false;
		if (current_hive.data[fieldB] == record[fieldA])
			return true;

		return false;
	},

	/**
	 * Checks if the current user is a mod of the current hive
	 * @param {Ext.data.Record} record The record to check
	 */
	isHiveMod						: function() {
		// check if anyone is logged in
		var current_user = this.getCurrentUser() || null;
		if (!current_user)
			return false;

		// check for current hive/membership
		var current_hive = this.getCurrentHive() || null;
		if (!current_hive)
			return false;

		if (current_hive.data.access_level > 1)
			return true;

		return false;
	},

	/**
	 * Checks if the current user is the owner of the current hive
	 * @param {Ext.data.Record} record The record to check
	 */
	isHiveOwner						: function() {
		// check if anyone is logged in
		var current_user = this.getCurrentUser() || null;
		if (!current_user)
			return false;

		// check for current hive/membership
		var current_hive = this.getCurrentHive() || null;
		if (!current_hive)
			return false;

		if (current_hive.data.access_level > 2)
			return true;

		return false;
	},

	/**
	 * Checks if the current user has permission to edit/destroy a given record
	 * @param {Ext.data.Record} record The record which the user wants to destroy.
	 *                                 taken from an Ext.data.store
	 */
	hasPermission					: function(record) {
		var type = 1;
		if (typeof record == "boolean" && record == true) {
			type = 2;
		};

		// Get the logged in user, if cannot be found return false
		var current_user = this.getCurrentUser() || null;
		if (!current_user) {
			return false;
		};

		// Check if the logged in user is a moderator or owner of the current hive
		var current_hive = this.getCurrentHive() || null;
		if (!current_hive) {
			return false;
		};
		if (current_hive.data.access_level > type) {
			return true;
		};

		// Get the author_membership_id of the record and check if it is the same as the current user who
		// is logged in
		if (!record || typeof record == "boolean") {
			return false;
		};
		if (!record.data) {
			return false;
		};
		if (!record.data.author_membership_id) {
			return false;
		};
		if (current_hive.data.id == record.data.author_membership_id) {
			return true;
		};

		return false;
	},

	/**
	 * Overwrite the defalt sets title function so it doesn't update the document title ever.
	 */
	setsTitle						: Ext.emptyFn,

	handleHistoryChange				: function(token) {
		// Get the hive id, controller and action if specified in the window location hash
		var hiveId = (token.split('#')[1]) ? token.split('#')[1] : token
				.split('#')[0]
				|| null;

		if (!hiveId)
			return;

		// Get the current hive
		var hive = this.getCurrentHive() || null;

		// Get current hive id and check if it is the same
		if (hive) {
			if (hiveId != hive.data.hive.id) {
				this.getController('hives').fireAction('loadHive', null,
						[hiveId]
				);
			};
		} else {
			this.getController('hives').fireAction('loadHive', null, [hiveId]);
		};

		// Get the controller + action from the token and try and and match it
		var newToken;
		var controller = token.split('/')[1];
		var action = token.split('/')[2];
		var id = token.split('/')[3];

		if (controller && action && id) {
			newToken = controller + "/" + action + "/" + id;
		};
		if (controller && action && !id) {
			newToken = controller + "/" + action;
		};
		if (controller && !action && !id) {
			newToken = controller;
		};

		// Try and find the controller + action, and if we can fire off the dispatch
		var match = this.router.recognise(newToken);
		if (match) {
			// sets document title
			var title = String.format("Kohive : {0}",
					this.getCurrentHive().data.hive.title
			);
			if (controller != undefined)
				title += String.format(" : {0}", (match.controller
								&& this.getController(match.controller) && this
								.getController(match.controller).title)
								? this.getController(match.controller).title
								: controller.titleize());
			document.title = title;

			this.dispatch(match);
		} else {
			// sets document title
			var title = String.format("Kohive : {0}",
					this.getCurrentHive().data.hive.title
			);
			document.title = title;
		};
	},

	/**
	 * Debug helper method to log fired events for a specific object
	 * @param {Observable} observable Any object that extends Ext.util.Observable
	 * @param {String} name Name to identify the log messages in the console 
	 */
	logFiredEvents					: function(observable, name) {
		Ext.util.Observable.capture(observable, function(eventName, el) {
					console.info(name + ' Event:', eventName, el);
				}, this);
	},

	/**
	 * Locally set stores for the memberpanel and application launcher. this is needed
	 * so when both are available when they need to be shown
	 */
	storeA							: null,
	storeB							: null,

	/**
	 * Checks if the members are loaded and the applications have loaded, and if they have
	 * it shows both at the same time
	 */
	showMembersAndApplications		: function(memberPanel,
			applicationLauncher, storeA, storeB) {
		Kohive.OS.log('showMembersAndApplications', arguments);
		var membersController = this.getController('members');
		var memberPanel = memberPanel || this.getMemberPanel();
		var applicationLauncher = applicationLauncher
				|| this.getApplicationLauncher();

		// if (storeA) this.storeA = storeA;
		// if (storeB) this.storeB = storeB;

		// fade them in
		// if (this.storeA && this.storeB) {
		if (storeA) {
			memberPanel.setStore(storeA);
			memberPanel.gogogo.defer(1000, memberPanel);
		};
		if (storeB) {
			applicationLauncher.setStore(storeB);
			applicationLauncher.gogogo.defer(1000, applicationLauncher);
		};

		// Kohive.OS.getController('members').loaded = false;
		// applicationLauncher.loaded = false;
		// };
	},

	/**
	* TODO: A hacky method to prepend the /memberships/:membership_id/ segment to the front of an AJAX
	* request url.  This really ought to be handled by the model, so factor it out of here when possible
	* @param {String} url The url to append to the memberships scope
	* @return {String} The fully scoped url
	*/
	scopedUrl						: function(url) {
		return String.format("/memberships/{0}/{1}", this.getCurrentHive()
						.get('id'), url);
	},

	// on: function(a) {
	// if (a == "before-ping") console.log('on');
	// ExtMVC.OS.superclass.on.apply(this, arguments);
	// },
	// 
	// un: function(a) {
	// if (a == "before-ping") console.log('un');
	// ExtMVC.OS.superclass.un.apply(this, arguments);
	// }
	log								: function() {
		if (this.logging)
			console.log.apply(this, arguments);
	},

	/**
	 * Adds the desktop stickies wrapper to the desktop so they can be added/deleted accordingly.
	 */
	addStickiesWrapperToDesktop		: function() {
		// Add the desktop stickies container
		this.desktopStickiesEl = Ext.getBody().createChild({
					cls	: 'desktop-stickies',
					id	: 'kohive-desktop-stickies'
				});

		var os = this;

		this.stickiesDropTarget = new Ext.dd.DropTarget(Ext.getBody(), {
					ddGroup		: 'desktop-stickies',
					notifyOver	: function(source, e, data) {
						if (os.stickyDropAllowed(data.sticky, e)) {
							return Ext.dd.DropTarget.prototype.dropAllowed;
						} else {
							return Ext.dd.DropTarget.prototype.dropNotAllowed;
						};
					},

					notifyDrop	: function(source, e, data) {
						if (os.stickyDropAllowed(data.sticky, e)) {
							os.onValidStickyDrop(source, e, data);
							return true;
							// return stack.fireEvent('carddropped', stack, data.card);
						} else {
							return false;
						}
					}
				});

		this.desktopStickiesDataview = new Ext.DataView({
			renderTo		: 'kohive-desktop-stickies',
			emptyText		: '',
			itemSelector	: '.x-pod',
			overClass		: 'x-over',
			tpl				: Kohive.models.DesktopSticky.dataView,
			store			: Kohive.models.DesktopSticky.findAll({
						autoLoad	: false
					}),
			listeners		: {
				scope	: this,
				// 'mouseover' : this.viewOnMouseOver,
				// 'mouseout' : this.viewOnMouseOut,
				'click'	: function(dataview, index, node, e) {
					var el = Ext.get(node), target = Ext.get(e.getTarget()), record = dataview
							.getRecord(node);

					// Delete
					if (target.hasClass('x-delete')
							|| target.parent().hasClass('x-delete')) {
						var contentEl = el.child('.x-content-wrap') || el;

						return Ext.Msg.show({
							title	: '',
							msg		: Ext.ux.Translator
									.translate('app_desktop_stickies_destroy_desc'),
							buttons	: {
								yes	: Ext.ux.Translator.translate('remove'),
								no	: Ext.ux.Translator.translate('keep')
							},
							scope	: this,
							fn		: function(btn) {
								if (btn == "yes")
									Kohive.OS.onDestroyDesktopSticky(record,
											dataview.store, contentEl
									);
							}
						}
						);
					};
				}
			}
		}
		);

		// Resize the background on window resize
		var obj = this;
		$(window).bind('resize', function() {
					obj.desktopStickiesEl.setWidth(Ext.getBody().getWidth());
					obj.desktopStickiesEl.setHeight(Ext.getBody().getHeight()
							- 40);
				}
		);
		obj.desktopStickiesEl.setWidth(Ext.getBody().getWidth());
		obj.desktopStickiesEl.setHeight(Ext.getBody().getHeight() - 40);
	},

	/**
	 * 
	 */
	onValidStickyDrop				: function(source, e, data) {
		var dragEl = Ext.get(source.getDragEl()), el = Ext.get(source.getEl())
				.parent(), sticky = data.sticky, view = data.view, store = Kohive.OS.desktopStickiesDataview.store;

		// remove the drag el
		// dragEl.remove();

		// create a new desktop sticky record
		var record = new Kohive.models.DesktopSticky({
					hive_id					: Kohive.OS.getCurrentHiveId(),
					sticky_id				: sticky.get('id'),
					author_membership_id	: Kohive.OS.getCurrentHive()
							.get('id')
				});

		// show saving on the index view
		view.showLoading(Ext.ux.Translator
				.translate('app_statusbar_saving_to_desktop'));

		// save the record
		record.save({
					scope	: this,
					url		: Kohive.OS.scopedUrl('desktop_stickies'),
					success	: function() {
						view.showSuccess();
						store.load();
					},
					failure	: function(record, response) {
						view.showFailure();

						// decode the response
						var response = Ext.decode(response.responseText);

						// check what the error is and show it in a ext.msg
						if (response && response.errors
								&& response.errors.length > 0)
							Ext.Msg.alert('', Ext.ux.Translator
											.translate(response.errors[0]));
					}
				});
	},

	/**
	 * 
	 */
	stickyDropAllowed				: function(sticky, e) {
		var store = Kohive.OS.desktopStickiesDataview.store, duplicate = false;

		store.each(function(record) {
					if (record.get('sticky_id') == sticky.data.id)
						duplicate = true;
				}, this);

		if (duplicate === true)
			return false;
		else
			return true;
	},

	/**
	 * Updates the stickies on the desktop
	 */
	updateDesktopStickies			: function() {
		this.desktopStickiesDataview.el.fadeOut({
					scope		: this,
					callback	: function() {
						this.desktopStickiesDataview.store.proxy.conn.url = this
								.scopedUrl('desktop_stickies');
						this.desktopStickiesDataview.store.load({
									scope		: this,
									callback	: function() {
										this.desktopStickiesDataview.el
												.fadeIn();
									}
								});
					}
				}
		);
	},

	onDestroyDesktopSticky			: function(record, store, contentEl) {
		var id = record.get('id');

		var u = new Kohive.models.DesktopSticky({
					id	: id
				});
		u.destroy({
					url		: Kohive.OS.scopedUrl('desktop_stickies/'
							+ record.get('id')),
					scope	: this,
					success	: Kohive.OS.onDestroyDesktopStickySuccess
							.createDelegate(Kohive.OS, [store, contentEl]),
					failure	: Kohive.OS.onDestroyDesktopStickyFailure
				});
	},

	onDestroyDesktopStickySuccess	: function(store, contentEl) {
		contentEl.fadeOut({
					duration	: 0.5,
					scope		: this,
					callback	: function() {
						store.reload();
					}
				});
	},

	onDestroyDesktopStickyFailure	: function() {
		Ext.Msg.alert('Delete Failed', Ext.ux.Translator
						.translate('something_wrong'));
	},

	/**
	 * Checks this.currentUser for the 'shown_first_login' param and fires off an event
	 * if it is a new user
	 */
	checkForFirstLogin				: function(user) {
		var user = user || Kohive.OS.getCurrentUser();
		if (!user.get('shown_first_login'))
			this.fireEvent('show-first-login', user);
	}
}
);

Kohive.OS = new Kohive.OS();

Ext.ns('Kohive.views.os');